# -*- coding: utf-8 -*-

from hlm.node import *

from ip.fabrics import ChannelExecOpFabric


class NodeRouterNanoOp(Node):
    def initialize(self, params: ObjectDict) -> None:
        params.routing_map: 'List.List.int'
        # Create the receiver.
        self.port.receiver = self.port_channel_receiver(ChannelExecOpFabric)
        # Build the mask map.
        self.reg.mask_map = [0 for _ in range(len(params.routing_map))]
        for ii in range(len(params.routing_map)):
            # Based on the routing list, add mask.
            for routing_id in params.routing_map[ii]:
                self.reg.mask_map[ii] |= (1 << routing_id)
        # Create the output ports.
        self.port.senders = [self.port_channel_sender(ChannelExecOpFabric)
                             for _ in range(len(params.routing_map))]
        # Prepare the router state.
        self.reg.is_routing = False
        self.reg.deploy = [False for _ in range(len(params.routing_map))]

    tasks = ['task_receive_nano_op',
             'task_dispatch_nano_op']

    def task_receive_nano_op(self):
        # Check validation.
        if self.reg.is_routing or self.port.receiver.Bus.is_any_empty():
            return
        # Fetch the nano op.
        self.reg.nano_op = self.port.receiver.Bus.get()
        # Based on the peer id in the nano op, calculate the routing state.
        for ii in range(len(self.reg.deploy)):
            self.reg.deploy[ii] = (self.reg.nano_op.peer_id & self.reg.mask_map[ii]) > 0
        # Set routing flag.
        self.reg.is_routing = True

    def task_dispatch_nano_op(self):
        # Check routing flag.
        if not self.reg.is_routing:
            return
        # Clear the working flag.
        self.reg.is_working = False
        for ii in range(len(self.reg.deploy)):
            if self.reg.deploy[ii] and not self.port.senders[ii].Bus.is_any_full():
                # Deploy the nano op.
                self.port.senders[ii].Bus.put(nano_op=self.reg.nano_op)
                # Clear the deploy flag.
                self.reg.deploy[ii] = False
            # Update working states.
            self.reg.is_working = self.reg.is_working or self.reg.deploy[ii]
        # Update the routing states.
        self.reg.is_routing = self.reg.is_working